﻿using System.Reflection.Emit;
using System;
using System.Collections.Generic;
using System.Windows.Threading;
using System.Reflection;
using System.Windows;
namespace ProxyViewModel.Emitors {
	public class DispatcherEmitor : EmitorBase {
		public DispatcherEmitor(TypeBuilder builder, Type operatable, IDictionary<string, object> parameters)
			: base(builder, operatable, parameters) { }

		protected override void EmitContent() {
			TypeBuilder.AddInterfaceImplementation(typeof(IDispatcherContainer));
			FieldBuilder dispatcherField = TypeBuilder.DefineField("_initialDispatcher", typeof(Dispatcher), FieldAttributes.Private);

			CallMethodOnConstruction(InitializeDispatcher(dispatcherField));
			GenerateDispatcherProperty(dispatcherField);
		}

		private void GenerateDispatcherProperty(FieldBuilder dispatcherField) {
			PropertyBuilder dispatcherProperty = TypeBuilder.DefineProperty("Dispatcher",
				PropertyAttributes.HasDefault, typeof(bool), new Type[] { typeof(bool) });

			MethodBuilder getMethod = TypeBuilder.DefineMethod("get_Dispatcher", MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual |
				MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Dispatcher), Type.EmptyTypes);

			ILGenerator il = getMethod.GetILGenerator();
			il.Emit(OpCodes.Ldarg_0);
			il.Emit(OpCodes.Ldfld, dispatcherField);
			il.Emit(OpCodes.Nop);
			il.Emit(OpCodes.Ret);

			dispatcherProperty.SetGetMethod(getMethod);
		}

		private MethodBuilder InitializeDispatcher(FieldBuilder initialDispatcher) {
			MethodBuilder initializeDispatcherMethod = TypeBuilder.DefineMethod("InitializeDispatcher", MethodAttributes.Private, CallingConventions.Standard);

			ILGenerator il = initializeDispatcherMethod.GetILGenerator();
#if SILVERLIGHT
			il.DeclareLocal(typeof(Deployment));
#endif
			il.Emit(OpCodes.Ldarg_0);
#if SILVERLIGHT
			il.Emit(OpCodes.Call, typeof(Deployment).GetMethod("get_Current"));
			il.Emit(OpCodes.Stloc_0);
			il.Emit(OpCodes.Nop);
			il.Emit(OpCodes.Ldloc_0);
			il.Emit(OpCodes.Call, typeof(Deployment).GetMethod("get_Dispatcher"));
#else
			il.Emit(OpCodes.Call, typeof(Dispatcher).GetMethod("get_CurrentDispatcher"));
#endif
			il.Emit(OpCodes.Stfld, initialDispatcher);
			il.Emit(OpCodes.Nop);
			il.Emit(OpCodes.Ret);

			return initializeDispatcherMethod;
		}
	}
}
